// Filename: spriteParticleRenderer.I
// Created by:  charles (13Jul00)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University.  All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license.  You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////
//    Function : SpriteParticleRenderer::set_texture
//      Access : Published
// Description : Sets the renderer up to render the entire texture
//               image.  The scale of each particle is based on the
//               size of the texture in each dimension, modified by
//               texels_per_unit.
//
//               Used to set the size of the particles.  Will clear
//               all previously loaded textures and animations.
////////////////////////////////////////////////////////////////////
INLINE void SpriteParticleRenderer::
set_texture(Texture *tex, PN_stdfloat texels_per_unit) {
  if (tex != (Texture *)NULL) {
    // Clear all texture information
    _anims.clear();

    // Insert the single texture
    _anims.push_back(new SpriteAnim(tex,LTexCoord(0.0f, 0.0f),LTexCoord(1.0f, 1.0f)));

    // We scale the particle size by the size of the texture.
    set_size(tex->get_x_size() / texels_per_unit,
             tex->get_y_size() / texels_per_unit);
    get_last_anim()->set_source_info(tex->get_filename());    
  }
  init_geoms();
}

////////////////////////////////////////////////////////////////////
//    Function : SpriteParticleRenderer::add_texture
//      Access : Published
// Description : Adds texture to image pool, effectively creating a 
//               single frame animation that can be selected at 
//               particle birth.  This should only be called after
//               a previous call to set_texture().
////////////////////////////////////////////////////////////////////
INLINE void SpriteParticleRenderer::
add_texture(Texture *tex, PN_stdfloat texels_per_unit, bool resize) {
  if (_anims.size() == 0) {
    set_texture(tex, texels_per_unit);
  } else {
    if(tex != (Texture *)NULL) {
      if (tex != (Texture *)NULL) {
        _anims.push_back(new SpriteAnim(tex,LTexCoord(0.0f, 0.0f),LTexCoord(1.0f, 1.0f)));
      }
      if(resize) {
        // We scale the particle size by the size of the texture.
        set_size(tex->get_x_size() / texels_per_unit,
                 tex->get_y_size() / texels_per_unit);
      }
      get_last_anim()->set_source_info(tex->get_filename());
      init_geoms();
    }
  }
}

////////////////////////////////////////////////////////////////////
//    Function : SpriteParticleRenderer::remove_animation
//      Access : Published
// Description : Removes an animation texture set from the renderer.
////////////////////////////////////////////////////////////////////
INLINE void SpriteParticleRenderer::
remove_animation(const int n) {
  nassertv(n < (int)_anims.size());
  int i,j;

  for (i = 0; i < (int)_anims.size(); ++i) {
    for (j = 0; j < (int)_anim_size[i]; ++j) {
      _sprites[i][j]->clear_vertices();
    }
  }

  _anims.erase(_anims.begin()+n);
  _animation_removed = true;
  init_geoms();
}

////////////////////////////////////////////////////////////////////
//    Function : SpriteParticleRenderer::set_ll_uv
//      Access : public
// Description : Sets the UV coordinate of the lower-left corner of
//               all the sprites generated by this renderer.  Normally
//               this is (0, 0), but it might be set to something else
//               to use only a portion of the texture.
////////////////////////////////////////////////////////////////////
INLINE void SpriteParticleRenderer::
set_ll_uv(const LTexCoord &ll_uv) {
  set_ll_uv(ll_uv,0,0);
}

////////////////////////////////////////////////////////////////////
//    Function : SpriteParticleRenderer::set_ll_uv
//      Access : public
// Description : Sets the UV coordinate of the lower-left corner of
//               all the sprites generated by this renderer.  Normally
//               this is (0, 0), but it might be set to something else
//               to use only a portion of the texture.
////////////////////////////////////////////////////////////////////
INLINE void SpriteParticleRenderer::
set_ll_uv(const LTexCoord &ll_uv, const int anim, const int frame) {
  if(anim < (int)_anims.size() && frame < (int)_anims[anim]->get_num_frames()) {
    _anims[anim]->set_ll(frame,ll_uv);
  }
}

////////////////////////////////////////////////////////////////////
//    Function : SpriteParticleRenderer::set_ur_uv
//      Access : public
// Description : Sets the UV coordinate of the upper-right corner of
//               all the sprites generated by this renderer.  Normally
//               this is (1, 1), but it might be set to something else
//               to use only a portion of the texture.
////////////////////////////////////////////////////////////////////
INLINE void SpriteParticleRenderer::
set_ur_uv(const LTexCoord &ur_uv) {
  set_ur_uv(ur_uv,0,0);
}

////////////////////////////////////////////////////////////////////
//    Function : SpriteParticleRenderer::set_ur_uv
//      Access : public
// Description : Sets the UV coordinate of the upper-right corner of
//               all the sprites generated by this renderer.  Normally
//               this is (1, 1), but it might be set to something else
//               to use only a portion of the texture.
////////////////////////////////////////////////////////////////////
INLINE void SpriteParticleRenderer::
set_ur_uv(const LTexCoord &ur_uv, const int anim, const int frame) {
  if(anim < (int)_anims.size() && frame < (int)_anims[anim]->get_num_frames()) {
    _anims[anim]->set_ur(frame,ur_uv);
  }
}

////////////////////////////////////////////////////////////////////
//    Function : SpriteParticleRenderer::set_size
//      Access : public
// Description : Sets the size of each particle in world units.
////////////////////////////////////////////////////////////////////
INLINE void SpriteParticleRenderer::
set_size(PN_stdfloat width, PN_stdfloat height) {
  _width = width;
  _height = height;
  init_geoms();
}

////////////////////////////////////////////////////////////////////
// Function : SpriteParticleRenderer::set_color
//   Access : public
////////////////////////////////////////////////////////////////////
INLINE void SpriteParticleRenderer::
set_color(const LColor &color) {
  _color = color;
  _color_interpolation_manager->set_default_color(_color);
}

////////////////////////////////////////////////////////////////////
// Function : SpriteParticleRenderer::set_x_scale_flag
//   Access : public
////////////////////////////////////////////////////////////////////
INLINE void SpriteParticleRenderer::
set_x_scale_flag(bool animate_x_ratio) {
  _animate_x_ratio = animate_x_ratio;
  init_geoms();
}

////////////////////////////////////////////////////////////////////
// Function : SpriteParticleRenderer::set_y_scale_flag
//   Access : public
////////////////////////////////////////////////////////////////////
INLINE void SpriteParticleRenderer::
set_y_scale_flag(bool animate_y_ratio) {
  _animate_y_ratio = animate_y_ratio;
  init_geoms();
}

////////////////////////////////////////////////////////////////////
// Function : SpriteParticleRenderer::set_anim_angle_flag
//   Access : public
////////////////////////////////////////////////////////////////////
INLINE void SpriteParticleRenderer::
set_anim_angle_flag(bool animate_theta) {
  _animate_theta = animate_theta;
  init_geoms();
}

////////////////////////////////////////////////////////////////////
// Function : SpriteParticleRenderer::set_initial_x_scale
//   Access : public
////////////////////////////////////////////////////////////////////
INLINE void SpriteParticleRenderer::
set_initial_x_scale(PN_stdfloat initial_x_scale) {
  _initial_x_scale = initial_x_scale;
  init_geoms();
}

////////////////////////////////////////////////////////////////////
// Function : SpriteParticleRenderer::set_final_x_scale
//   Access : public
////////////////////////////////////////////////////////////////////
INLINE void SpriteParticleRenderer::
set_final_x_scale(PN_stdfloat final_x_scale) {
  _final_x_scale = final_x_scale;
}

////////////////////////////////////////////////////////////////////
// Function : SpriteParticleRenderer::set_initial_y_scale
//   Access : public
////////////////////////////////////////////////////////////////////
INLINE void SpriteParticleRenderer::
set_initial_y_scale(PN_stdfloat initial_y_scale) {
  _initial_y_scale = initial_y_scale;
  init_geoms();
}

////////////////////////////////////////////////////////////////////
// Function : SpriteParticleRenderer::set_final_y_scale
//   Access : public
////////////////////////////////////////////////////////////////////
INLINE void SpriteParticleRenderer::
set_final_y_scale(PN_stdfloat final_y_scale) {
  _final_y_scale = final_y_scale;
}

////////////////////////////////////////////////////////////////////
// Function : SpriteParticleRenderer::set_nonanimated_theta
//   Access : public
////////////////////////////////////////////////////////////////////
INLINE void SpriteParticleRenderer::
set_nonanimated_theta(PN_stdfloat theta) {
  _theta = theta;
  init_geoms();
}

////////////////////////////////////////////////////////////////////
// Function : SpriteParticleRenderer::set_alpha_blend_method
//   Access : public
////////////////////////////////////////////////////////////////////
INLINE void SpriteParticleRenderer::
set_alpha_blend_method(ParticleRendererBlendMethod bm) {
  _blend_method = bm;
}

////////////////////////////////////////////////////////////////////
// Function : SpriteParticleRenderer::set_alpha_disable
//   Access : public
////////////////////////////////////////////////////////////////////
INLINE void SpriteParticleRenderer::
set_alpha_disable(bool ad) {
  _alpha_disable = ad;
}

////////////////////////////////////////////////////////////////////
// Function : SpriteParticleRenderer::set_animate_frames_enable
//   Access : public
////////////////////////////////////////////////////////////////////
INLINE void SpriteParticleRenderer::
set_animate_frames_enable(bool an) {
  _animate_frames = an;
}

////////////////////////////////////////////////////////////////////
// Function : SpriteParticleRenderer::set_animate_frames_rate
//   Access : public
////////////////////////////////////////////////////////////////////
INLINE void SpriteParticleRenderer::
set_animate_frames_rate(PN_stdfloat r) {
  nassertv( r >= 0.0);
  _animate_frames_rate = r;
}

////////////////////////////////////////////////////////////////////
// Function : SpriteParticleRenderer::set_animate_frames_index
//   Access : public
//  Purpose : Sets the frame to be used when animation is disabled.
////////////////////////////////////////////////////////////////////
INLINE void SpriteParticleRenderer::
set_animate_frames_index(int i) {
  nassertv(i < (int)_anims[0]->get_num_frames());
  _animate_frames_index = i;
}

////////////////////////////////////////////////////////////////////
// Function : SpriteParticleRenderer::get_texture
//   Access : public
////////////////////////////////////////////////////////////////////
INLINE Texture *SpriteParticleRenderer::
get_texture() const {
  return get_texture(0,0);
}

////////////////////////////////////////////////////////////////////
// Function : SpriteParticleRenderer::get_texture
//   Access : public
////////////////////////////////////////////////////////////////////
INLINE Texture *SpriteParticleRenderer::
get_texture(const int anim, const int frame) const {
  if(_anims.size() == 0) {
    return (Texture*)NULL;
  }
  nassertr(anim < (int)_anims.size() && anim >= 0, (Texture*)NULL);
  nassertr(frame < (int)_anims[anim]->get_num_frames() && frame >= 0,_anims[anim]->get_frame(0));
  return _anims[anim]->get_frame(frame);
}

INLINE int SpriteParticleRenderer::
get_num_anims() const {
  return _anims.size();
}

INLINE SpriteAnim *SpriteParticleRenderer::
get_anim(const int n) const {
  nassertr(n < (int)_anims.size(), (SpriteAnim*)NULL);
  return _anims[n];
}

INLINE SpriteAnim *SpriteParticleRenderer::
get_last_anim() const {
  if (_anims.size()) {
    return *(_anims.end()-1);
  } else {
    return (SpriteAnim *)NULL;
  }
}

////////////////////////////////////////////////////////////////////
//    Function : SpriteParticleRenderer::get_ll_uv
//      Access : public
// Description : Returns the UV coordinate of the lower-left corner;
//               see set_ll_uv().
////////////////////////////////////////////////////////////////////
INLINE LTexCoord SpriteParticleRenderer::
get_ll_uv() const {
  return get_ll_uv(0,0);
}

////////////////////////////////////////////////////////////////////
//    Function : SpriteParticleRenderer::get_ll_uv
//      Access : public
// Description : Returns the UV coordinate of the lower-left corner;
//               see set_ll_uv().
////////////////////////////////////////////////////////////////////
INLINE LTexCoord SpriteParticleRenderer::
get_ll_uv(const int anim, const int frame) const {
  int a = anim < (int)_anims.size()?anim:0;
  int f = frame < (int)_anims[a]->get_num_frames()?frame:0;
  return _anims[a]->get_ll(f);
}

////////////////////////////////////////////////////////////////////
//    Function : SpriteParticleRenderer::get_ur_uv
//      Access : public
// Description : Returns the UV coordinate of the lower-left corner;
//               see set_ur_uv().
////////////////////////////////////////////////////////////////////
INLINE LTexCoord SpriteParticleRenderer::
get_ur_uv() const {
  return get_ur_uv(0,0);
}

////////////////////////////////////////////////////////////////////
//    Function : SpriteParticleRenderer::get_ur_uv
//      Access : public
// Description : Returns the UV coordinate of the upper-right corner;
//               see set_ur_uv().
////////////////////////////////////////////////////////////////////
INLINE LTexCoord SpriteParticleRenderer::
get_ur_uv(const int anim, const int frame) const {
  int a = anim < (int)_anims.size()?anim:0;
  int f = frame < (int)_anims[a]->get_num_frames()?frame:0;
  return _anims[a]->get_ur(f);
}

////////////////////////////////////////////////////////////////////
//    Function : SpriteParticleRenderer::get_width
//      Access : public
// Description : Returns the width of each particle in world units.
////////////////////////////////////////////////////////////////////
INLINE PN_stdfloat SpriteParticleRenderer::
get_width() const {
  return _width;
}

////////////////////////////////////////////////////////////////////
//    Function : SpriteParticleRenderer::get_height
//      Access : public
// Description : Returns the height of each particle in world units.
////////////////////////////////////////////////////////////////////
INLINE PN_stdfloat SpriteParticleRenderer::
get_height() const {
  return _height;
}

////////////////////////////////////////////////////////////////////
// Function : SpriteParticleRenderer::get_color
//   Access : public
////////////////////////////////////////////////////////////////////
INLINE LColor SpriteParticleRenderer::
get_color() const {
  return _color;
}

////////////////////////////////////////////////////////////////////
// Function : SpriteParticleRenderer::get_x_scale_flag
//   Access : public
////////////////////////////////////////////////////////////////////
INLINE bool SpriteParticleRenderer::
get_x_scale_flag() const {
  return _animate_x_ratio;
}

////////////////////////////////////////////////////////////////////
// Function : SpriteParticleRenderer::get_y_scale_flag
//   Access : public
////////////////////////////////////////////////////////////////////
INLINE bool SpriteParticleRenderer::
get_y_scale_flag() const {
  return _animate_y_ratio;
}

////////////////////////////////////////////////////////////////////
// Function : SpriteParticleRenderer::get_anim_angle_flag
//   Access : public
////////////////////////////////////////////////////////////////////
INLINE bool SpriteParticleRenderer::
get_anim_angle_flag() const {
  return _animate_theta;
}

////////////////////////////////////////////////////////////////////
// Function : SpriteParticleRenderer::get_initial_x_scale
//   Access : public
////////////////////////////////////////////////////////////////////
INLINE PN_stdfloat SpriteParticleRenderer::
get_initial_x_scale() const {
  return _initial_x_scale;
}

////////////////////////////////////////////////////////////////////
// Function : SpriteParticleRenderer::get_final_x_scale
//   Access : public
////////////////////////////////////////////////////////////////////
INLINE PN_stdfloat SpriteParticleRenderer::
get_final_x_scale() const {
  return _final_x_scale;
}

////////////////////////////////////////////////////////////////////
// Function : SpriteParticleRenderer::get_initial_y_scale
//   Access : public
////////////////////////////////////////////////////////////////////
INLINE PN_stdfloat SpriteParticleRenderer::
get_initial_y_scale() const {
  return _initial_y_scale;
}

////////////////////////////////////////////////////////////////////
// Function : SpriteParticleRenderer::get_final_y_scale
//   Access : public
////////////////////////////////////////////////////////////////////
INLINE PN_stdfloat SpriteParticleRenderer::
get_final_y_scale() const {
  return _final_y_scale;
}

////////////////////////////////////////////////////////////////////
// Function : SpriteParticleRenderer::get_nonanimated_theta
//   Access : public
////////////////////////////////////////////////////////////////////
INLINE PN_stdfloat SpriteParticleRenderer::
get_nonanimated_theta() const {
  return _theta;
}

////////////////////////////////////////////////////////////////////
// Function : SpriteParticleRenderer::get_alpha_blend_method
//   Access : public
////////////////////////////////////////////////////////////////////
INLINE BaseParticleRenderer::ParticleRendererBlendMethod SpriteParticleRenderer::
get_alpha_blend_method() const {
  return _blend_method;
}

////////////////////////////////////////////////////////////////////
// Function : SpriteParticleRenderer::get_alpha_disable
//   Access : public
////////////////////////////////////////////////////////////////////
INLINE bool SpriteParticleRenderer::
get_alpha_disable() const {
  return _alpha_disable;
}

////////////////////////////////////////////////////////////////////
// Function : SpriteParticleRenderer::get_animate_frames_enable
//   Access : public
////////////////////////////////////////////////////////////////////
INLINE bool SpriteParticleRenderer::
get_animate_frames_enable() const {
  return _animate_frames;
}

////////////////////////////////////////////////////////////////////
// Function : SpriteParticleRenderer::get_animate_frames_rate
//   Access : public
////////////////////////////////////////////////////////////////////
INLINE PN_stdfloat SpriteParticleRenderer::
get_animate_frames_rate() const {
  return _animate_frames_rate;
}

////////////////////////////////////////////////////////////////////
// Function : SpriteParticleRenderer::get_animate_frames_index
//   Access : public
//  Purpose : Gets the frame to be used when animation is disabled.
////////////////////////////////////////////////////////////////////
INLINE int SpriteParticleRenderer::
get_animate_frames_index() const {
  return _animate_frames_index;
}

////////////////////////////////////////////////////////////////////
// Function : SpriteParticleRenderer::get_color_interpolation_manager
//   Access : public
////////////////////////////////////////////////////////////////////
INLINE ColorInterpolationManager* SpriteParticleRenderer::
get_color_interpolation_manager() const {
  return _color_interpolation_manager;
}
